"""
导入辅助器测试
==============

测试ImportHelper的各种功能
"""

from pathlib import Path
import sys

from unittest.mock import patch, MagicMock
import unittest
current_dir = Path(__file__).parent
project_root = current_dir.parents[3]
if str(project_root) not in sys.path:
    sys.path.insert(0, str(project_root))

from ..unified_path_manager import UnifiedPathManager
from ..import_helper import (
    ImportHelper,
    create_import_helper,
    get_relative_import_path,
    safe_import
)


class TestImportHelper(unittest.TestCase):
    """导入辅助器测试类"""
    
    def setUp(self):
        """测试前设置"""
        # 重置单例状态
        if hasattr(UnifiedPathManager, '_instance'):
            UnifiedPathManager._instance = None
        if hasattr(UnifiedPathManager, '_initialized'):
            UnifiedPathManager._initialized = False
        
        self.path_manager = UnifiedPathManager()
        self.import_helper = ImportHelper(self.path_manager)
    
    def tearDown(self):
        """测试后清理"""
        self.import_helper.clear_import_cache()
        
        if hasattr(UnifiedPathManager, '_instance'):
            UnifiedPathManager._instance = None
        if hasattr(UnifiedPathManager, '_initialized'):
            UnifiedPathManager._initialized = False
    
    def test_create_import_helper(self):
        """测试创建导入辅助器"""
        helper = create_import_helper(self.path_manager)
        self.assertIsInstance(helper, ImportHelper)
        self.assertIs(helper.path_manager, self.path_manager)
    
    def test_generate_relative_import(self):
        """测试生成相对导入路径"""
        # 测试从服务到shared模块的相对导入
        from_path = self.path_manager.backend_dir / "services" / "user_service" / "app" / "main.py"
        to_module = "shared.database"
        
        relative_path = self.import_helper.generate_relative_import(from_path, to_module)
        
        # 应该生成相对导入路径
        self.assertTrue(relative_path.startswith("."))
        self.assertTrue(relative_path.endswith("shared.database"))
    
    def test_generate_relative_import_from_directory(self):
        """测试从目录生成相对导入路径"""
        from_path = self.path_manager.backend_dir / "services" / "user_service" / "app"
        to_module = "shared.config"
        
        relative_path = self.import_helper.generate_relative_import(from_path, to_module)
        
        self.assertTrue(relative_path.startswith("."))
        self.assertTrue(relative_path.endswith("shared.config"))
    
    def test_generate_absolute_import_fallback(self):
        """测试绝对导入回退"""
        # 使用不在backend目录下的路径
        from_path = Path("/some/other/path/file.py")
        to_module = "shared.database"
        
        import_path = self.import_helper.generate_relative_import(from_path, to_module)
        
        # 应该回退到绝对导入
        self.assertTrue(import_path == "shared.database" or 
                       import_path == "shared.database")
    
    def test_dynamic_import_success(self):
        """测试成功的动态导入"""
        # 测试导入标准库模块
        os_module = self.import_helper.dynamic_import("os")
        import os
        self.assertIs(os_module, os)
    
    def test_dynamic_import_with_attribute(self):
        """测试带属性的动态导入"""
        # 测试导入模块的特定属性
        path_class = self.import_helper.dynamic_import("pathlib", "Path")
        from pathlib import Path
        self.assertIs(path_class, Path)
    
    def test_dynamic_import_failure(self):
        """测试导入失败"""
        with self.assertRaises(ImportError):
            self.import_helper.dynamic_import("nonexistent_module")
    
    def test_dynamic_import_attribute_error(self):
        """测试属性不存在"""
        with self.assertRaises(ImportError):  # ImportHelper将AttributeError转换为ImportError
            self.import_helper.dynamic_import("os", "nonexistent_attribute")
    
    def test_import_cache(self):
        """测试导入缓存"""
        # 第一次导入
        module1 = self.import_helper.dynamic_import("os")
        
        # 第二次导入应该使用缓存
        module2 = self.import_helper.dynamic_import("os")
        
        self.assertIs(module1, module2)
        
        # 检查缓存统计
        stats = self.import_helper.get_cache_stats()
        self.assertGreater(stats["cached_imports"], 0)
        self.assertIn("os", stats["cache_keys"])
    
    def test_import_cache_disabled(self):
        """测试禁用缓存的导入"""
        # 使用缓存导入
        module1 = self.import_helper.dynamic_import("os", use_cache=True)
        
        # 不使用缓存导入
        module2 = self.import_helper.dynamic_import("os", use_cache=False)
        
        # 应该是同一个模块（Python模块缓存）
        self.assertIs(module1, module2)
    
    def test_failed_import_cache(self):
        """测试失败导入的缓存"""
        # 第一次尝试导入不存在的模块
        with self.assertRaises(ImportError):
            self.import_helper.dynamic_import("nonexistent_module")
        
        # 第二次尝试应该直接从失败缓存返回
        with self.assertRaises(ImportError):
            self.import_helper.dynamic_import("nonexistent_module")
        
        stats = self.import_helper.get_cache_stats()
        self.assertGreater(stats["failed_imports"], 0)
        self.assertIn("nonexistent_module", stats["failed_keys"])
    
    def test_import_shared_module(self):
        """测试导入shared模块"""
        # 这个测试可能会失败，因为具体的shared模块可能不存在
        # 但我们可以测试路径生成是否正确
        try:
            module = self.import_helper.import_shared_module("os")  # 使用os作为测试
        except ImportError:
            # 预期的失败，因为shared.os不存在
            pass
        
        # 测试路径生成逻辑
        import_path = f"shared.test_module"
        # 这里主要测试逻辑，不实际导入
    
    def test_get_module_info(self):
        """测试获取模块信息"""
        info = self.import_helper.get_module_info("os")
        
        self.assertIsInstance(info, dict)
        self.assertIn("name", info)
        self.assertIn("file", info)
        self.assertIn("attributes", info)
        self.assertIn("functions", info)
        
        self.assertEqual(info["name"], "os")
    
    def test_get_module_info_failure(self):
        """测试获取不存在模块的信息"""
        info = self.import_helper.get_module_info("nonexistent_module")
        
        self.assertIsInstance(info, dict)
        self.assertIn("error", info)
        self.assertIn("module_path", info)
    
    def test_find_import_conflicts(self):
        """测试查找导入冲突"""
        # 测试已存在的模块
        conflicts = self.import_helper.find_import_conflicts("os")
        
        self.assertIsInstance(conflicts, list)
        # os模块在sys.modules中，应该有冲突记录
        if conflicts:
            self.assertIn("type", conflicts[0])
    
    def test_clear_import_cache(self):
        """测试清除导入缓存"""
        # 先导入一些模块
        self.import_helper.dynamic_import("os")
        
        # 尝试导入失败的模块
        try:
            self.import_helper.dynamic_import("nonexistent")
        except ImportError:
            pass
        
        # 检查缓存不为空
        stats_before = self.import_helper.get_cache_stats()
        self.assertGreater(stats_before["cached_imports"] + stats_before["failed_imports"], 0)
        
        # 清除缓存
        self.import_helper.clear_import_cache()
        
        # 检查缓存已清空
        stats_after = self.import_helper.get_cache_stats()
        self.assertEqual(stats_after["cached_imports"], 0)
        self.assertEqual(stats_after["failed_imports"], 0)


class TestUtilityFunctions(unittest.TestCase):
    """工具函数测试"""
    
    def test_get_relative_import_path(self):
        """测试缓存版本的相对导入路径生成器"""
        backend_dir = "/project/backend"
        from_path = "/project/backend/services/user_service/app/main.py"
        to_module = "shared.database"
        
        relative_path = get_relative_import_path(from_path, to_module, backend_dir)
        
        self.assertTrue(relative_path.startswith("."))
        self.assertTrue(relative_path.endswith("shared.database"))
    
    def test_get_relative_import_path_caching(self):
        """测试相对导入路径生成的缓存"""
        backend_dir = "/project/backend"
        from_path = "/project/backend/services/user_service/app/main.py"
        to_module = "shared.database"
        
        # 多次调用应该返回相同结果（测试缓存）
        path1 = get_relative_import_path(from_path, to_module, backend_dir)
        path2 = get_relative_import_path(from_path, to_module, backend_dir)
        
        self.assertEqual(path1, path2)
    
    def test_safe_import_success(self):
        """测试安全导入成功"""
        result = safe_import("os")
        import os
        self.assertIs(result, os)
    
    def test_safe_import_failure(self):
        """测试安全导入失败"""
        default_value = "default"
        result = safe_import("nonexistent_module", default=default_value)
        self.assertEqual(result, default_value)
    
    def test_safe_import_with_attribute_success(self):
        """测试安全导入属性成功"""
        result = safe_import("pathlib", "Path")
        from pathlib import Path
        self.assertIs(result, Path)
    
    def test_safe_import_with_attribute_failure(self):
        """测试安全导入属性失败"""
        default_value = "default"
        result = safe_import("os", "nonexistent_attribute", default=default_value)
        self.assertEqual(result, default_value)
    
    def test_safe_import_module_failure(self):
        """测试安全导入模块失败"""
        default_value = None
        result = safe_import("nonexistent.module", "SomeClass", default=default_value)
        self.assertIsNone(result)


if __name__ == '__main__':
    unittest.main(verbosity=2)
